package com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.impl;

import com.derbysoft.dswitch.adapter.ihg.common.utils.DateTimeUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.Translator;
import com.derbysoft.dswitch.adapter.ihg.dto.OTAHotelAvailRS;
import com.derbysoft.dswitch.adapter.ihg.dto.Rate;
import com.derbysoft.dswitch.adapter.ihg.dto.RoomRate;
import com.derbysoft.dswitch.dto.hotel.common.*;
import com.derbysoft.dswitch.dto.hotel.reservation.HotelReservationRS;
import com.derbysoft.dswitch.dto.hotel.reservation.ReservationRoomStayDTO;
import com.derbysoft.dswitch.remote.hotel.dto.HotelReservationRequest;
import com.derbysoft.dswitch.remote.hotel.dto.HotelReservationResponse;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;

/**
 * Created by: jason
 * Date: 2012-05-14
 */
@Component("hotelPreviewRSTranslatorV2")
public class HotelPreviewRSTranslatorV2Impl extends BaseTranslator
        implements Translator<OTAHotelAvailRS, HotelReservationResponse, HotelReservationRequest> {

    @Override
    public HotelReservationResponse translate(OTAHotelAvailRS hotelAvailResponse,
                                              HotelReservationRequest reservationRequest) {
        HotelReservationResponse hotelReservationResponse = new HotelReservationResponse();
        hotelReservationResponse.setTaskId(reservationRequest.getHeader().getTaskId());
        hotelReservationResponse.setHotelReservationRS(createHotelReservationRS(hotelAvailResponse, reservationRequest));
        return hotelReservationResponse;
    }

    private HotelReservationRS createHotelReservationRS(OTAHotelAvailRS hotelAvailResponse, HotelReservationRequest reservationRequest) {
        HotelReservationRS hotelReservationRS = new HotelReservationRS();
        CancelPolicyDTO cancelPolicy = createCancelPolicy(hotelAvailResponse, reservationRequest);
        if (cancelPolicy != null) {
            hotelReservationRS.setCancelPolicy(cancelPolicy);
        }
        hotelReservationRS.setHotelReservation(reservationRequest.getHotelReservationRQ().getHotelReservation());
        setRateInfo(hotelReservationRS, hotelAvailResponse, reservationRequest);
        hotelReservationRS.setErsp(reservationRequest.getHotelReservationRQ().getErsp());
        return hotelReservationRS;
    }

    private void setRateInfo(HotelReservationRS reservationRS,
                             OTAHotelAvailRS otaHotelAvailRS, HotelReservationRequest reservationRequest) {

        ReservationRoomStayDTO reservationRoomStayDTO = reservationRS.getHotelReservation().getRoomStaysList().get(0);
        RoomRate roomRate = findRoomRate(otaHotelAvailRS, reservationRequest);
        if (roomRate != null) {
            StayDateRangeDTO stayDateRange = reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getStayDateRange();
            String start = stayDateRange.getCheckin();
            String end = DateTimeUtils.formatDate(DateTimeUtils.addDays(DateTimeUtils.parse(stayDateRange.getCheckout()), -1));
            RoomRateDTO roomRateDTO = translateRoomRate(roomRate, otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getTimeSpan());
            reservationRoomStayDTO.setRoomRate(roomRateDTO);
            TotalDTO totalDTO = new TotalDTO();
            totalDTO.setTaxesList(translateTaxes(roomRate.getRates().getRate().get(0), start, end));
            totalDTO.setCurrency(roomRate.getRates().getRate().get(0).getBase().getCurrencyCode());
            totalDTO.setAmountBeforeTax(calcBeforeTax(roomRateDTO));
            totalDTO.setAmountAfterTax(calcAfterTax(roomRateDTO));
            reservationRoomStayDTO.setTotal(totalDTO);
        }
    }

    private Double calcAfterTax(RoomRateDTO roomRateDTO) {
        BigDecimal amount = BigDecimal.ZERO;
        for (RateDTO rateDTO : roomRateDTO.getRatesList()) {
            amount = amount.add(rateDTO.getAmountAfterTax() == null ? BigDecimal.ZERO : BigDecimal.valueOf(rateDTO.getAmountAfterTax()));
        }
        return amount.doubleValue();
    }

    private Double calcBeforeTax(RoomRateDTO roomRateDTO) {
        BigDecimal amount = BigDecimal.ZERO;
        for (RateDTO rateDTO : roomRateDTO.getRatesList()) {
            amount = amount.add(rateDTO.getAmountBeforeTax() == null ? BigDecimal.ZERO : BigDecimal.valueOf(rateDTO.getAmountBeforeTax()));
        }
        return amount.doubleValue();
    }

    private CancelPolicyDTO createCancelPolicy(OTAHotelAvailRS otaHotelAvailRS, HotelReservationRequest reservationRequest) {
        RoomRate roomRate = findRoomRate(otaHotelAvailRS, reservationRequest);
        if (roomRate == null
                || roomRate.getRates() == null
                || CollectionUtils.isEmpty(roomRate.getRates().getRate())) {
            return null;
        }
        Rate ihgRate = roomRate.getRates().getRate().get(0);
        CancelPolicyDTO cancelPolicy = convertCancelPolicy(ihgRate);
        if (cancelPolicy != null) {
            return cancelPolicy;
        }
        return null;
    }

    private RoomRate findRoomRate(OTAHotelAvailRS otaHotelAvailRS, HotelReservationRequest reservationRequest) {
        String ratePlanCode = reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getRatePlanCode();
        String roomTypeCode = reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getRoomTypeCode() + ratePlanCode;
        if (CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay())
                || otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates() == null
                || CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate())
                || otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate().get(0).getRates() == null
                || CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate().get(0).getRates().getRate())) {
            return null;
        }
        for (RoomRate roomRate : otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate()) {
            if (roomRate.getRatePlanCode().equals(ratePlanCode) && roomRate.getRoomTypeCode().equals(roomTypeCode)) {
                return roomRate;
            }
        }
        return null;
    }
}
